package com.zwh.se.constant_variable_operator;

import java.text.DecimalFormat;

/**
 * 位运算符:  &,|,^,~ , >>,<<,>>>
 * 其中 >>，<<，>>> 又称作"移位运算符"。因为它们的运算规则就是在二进制补码的基础上对数字进行平移。
 * <p>
 * 可以看到逻辑运算符都被纳入了位运算当中，这是因为所谓true和false底层存储的就是1bit，所以可以利用其特性来用作逻辑判断而已，本质上其实就是位运算
 * 如何区分逻辑运算符和位运算符：
 * 逻辑运算符：左右连接的是布尔类型的操作数
 * 位运算符：左右连接的是具体的数值
 * <p>
 * 本运算符只是为了加深理解，对于java程序员而言，需要使用到该知识的场景是几乎没有的。
 *
 * @author yexi
 */
public class BitwiseOperators {
    public static void main(String[] args) {

        DecimalFormat df = new DecimalFormat("0000");
        //表面:
        System.out.println(6 & 4);//4
        System.out.println(4 | 6);//6
        System.out.println(7 ^ 6);//1

        System.out.println("--------------------[0]逻辑运算的二进制判断本质--------------------");
        //实际:
        // &:称之为"与运算"。根据底层二进制来进行比较,双方同时为1结果为1,否则为0
        System.out.println(df.format(Integer.parseInt(Integer.toBinaryString(0B110 & 0B100))));
        // |:称之为"或运算"。据据底层二进制来进行比较,只要有1则为1,否则为0
        System.out.println(df.format(Integer.parseInt(Integer.toBinaryString(0B100 | 0B110))));
        // ^:称之为"异或运算"。据据底层二进制来进行比较,当比较双方数字相同时则为0,否则为1。英文为exclusive OR,缩写成XOR,数学符号为"⊕"
        // 例如:0 ^ 0 = 0 , 0 ^ 1= 1 , 1 ^ 0= 1 , 1 ^ 1= 0 。
        System.out.println(df.format(Integer.parseInt(Integer.toBinaryString(0B111 ^ 0B110))));
        //还有一些长得比较特殊的运算符,这些都是语法糖,跟 += 一样道理,就是先运算符执行后再赋值
        // |= 运算符：实际就是 |
        // &= 运算符：实际就是 &
        // ^= 运算符：实际就是 ^

        //移位运算符
        System.out.println("--------------------[1]正数左/右移运算--------------------");
        int oldNum = 20;
        System.out.println(Integer.toBinaryString(oldNum));//10100
        // >> 右移运算,将2进制整体往右移,出界的数字就舍弃掉,高位补0,由于二进制的特性,每少一位就意味着数字变成了原本的1/2,右移两位就变成了1/4
        int newNum = oldNum >> 2;
        System.out.println(newNum);//5
        System.out.println(Integer.toBinaryString(newNum));//101
        // << 左移运算,将2进制整体往左移,缺的低位数就补0,并由于二进制特性每补一位使得数字变为原本的2倍,因此变为4倍
        int finalNum = newNum << 2;
        System.out.println(finalNum);//20
        System.out.println(Integer.toBinaryString(finalNum));//10100


        System.out.println("--------------------[2]负数左/右移运算--------------------");
        int ngNum = -20;
        System.out.println(Integer.toBinaryString(ngNum));//11111111111111111111111111101100
        //负数：右移时高位补1
        int rightNgNum = ngNum >> 2;
        System.out.println(rightNgNum);//-5
        System.out.println(Integer.toBinaryString(rightNgNum));//11111111111111111111111111111011
        //负数：左移时不分正负数，同样低位补0
        int leftNgNum = ngNum << 2;
        System.out.println(leftNgNum);//-80
        System.out.println(Integer.toBinaryString(leftNgNum));//11111111111111111111111110110000


        System.out.println("--------------------[3]>>>：无符号右移运算--------------------");
        //没有无符号左移,因为只有右移会产生到底补1还是0的问题
        //无符号右移，也叫逻辑右移，即若该数为正，则高位补0，而若该数为负数，则右移后高位同样补0
        //正数时与普通的 >> 相同
        int rpSignNum = 20 >>> 2;
        System.out.println(rpSignNum);//5
        System.out.println(Integer.toBinaryString(rpSignNum));//101
        //负数时右移后高位同样补0
        int rmSignNum = -20 >>> 2;
        System.out.println(Integer.toBinaryString(-20));  //11111111  11111111   11111111   11101100
        System.out.println(rmSignNum); //1073741819
        System.out.println(Integer.toBinaryString(rmSignNum)); //00111111  11111111   11111111   11111011

        System.out.println("--------------------[4]~：按位取反运算符(取反包括符号位)--------------------");
        // 此运算符常用于创建掩码（mask）和过滤器（filter）等操作。
        int poNum = 20;
        System.out.println(Integer.toBinaryString(poNum));// 00000000 00000000 00000000 00010100
        poNum = ~poNum;
        System.out.println(poNum);
        System.out.println(Integer.toBinaryString(poNum));// 11111111 11111111 11111111 11101011


    }
}
